﻿/*************************************************************************************
 * 文 件 名:   HK_ResetName
 * 
 * 描    述:   该工具中包含了：根据指定字符串查找物体、替换选中物体名称中的指定字符串、对选中物体进行重命名
 * 
 * 版    本：  V1.0
 * 创 建 者：  京产肠饭
 * 创建时间：  2021/8/26
 * 链   接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;

public class HK_ResetName : EditorWindow
{
    //选择了弹出window复选框下的哪个
    int popupIndex = 2;
    string[] popupNameArray = { "Find", "Repalce", "Rename" };
    int[] popupIndexArray = { 0, 1, 2, 3 };

    //方便以后维护,保证上面两个数组顺序和枚举里的顺序对应即可
    enum PopupIndex { Find, Repalce, NewName };

    //查找输入框
    string findInput;
    //替换输入框
    string repalceInput;

    string newNameInput;
    int startIndex;

    static GameObject[] selectedObjs;

    static MethodInfo clearMethod = null;

    [MenuItem("HKTools/Rename")]
    static void Init()
    {
        //弹出窗口
        HK_ResetName resetNameWindow = GetWindow<HK_ResetName>("FindOrReplace");
        resetNameWindow.Show();
    }

    void OnGUI()
    {
        EditorGUILayout.Space(15);

        popupIndex = EditorGUILayout.IntPopup("请选择功能:", popupIndex, popupNameArray, popupIndexArray);

        EditorGUILayout.Space();
        //查询
        if (popupIndex == (int)PopupIndex.Find)
        {
            findInput = EditorGUILayout.TextField("查询:", findInput);

            EditorGUILayout.Space();
            //创建一个按钮
            if (GUILayout.Button("查找", GUILayout.Width(55)))
            {
                Undo.RecordObjects(Selection.objects, "Find");
                FindOrReplace((int)PopupIndex.Find, findInput, repalceInput);
            }
        }
        //替换
        else if (popupIndex == (int)PopupIndex.Repalce)
        {
            findInput = EditorGUILayout.TextField("查询:", findInput);

            EditorGUILayout.Space();

            repalceInput = EditorGUILayout.TextField("替换为:", repalceInput);

            EditorGUILayout.Space();

            //创建一个按钮
            if (GUILayout.Button("替换", GUILayout.Width(55)))
            {
                Undo.RecordObjects(Selection.objects, "Replace");
                FindOrReplace((int)PopupIndex.Repalce, findInput, repalceInput);
            }
        }
        //新命名
        else if (popupIndex == (int)PopupIndex.NewName)
        {
            newNameInput = EditorGUILayout.TextField("重新命名:", newNameInput);

            startIndex = EditorGUILayout.IntField("初始编号：", startIndex);

            EditorGUILayout.Space();

            //创建一个按钮
            if (GUILayout.Button("确定", GUILayout.Width(55)))
            {
                Undo.RecordObjects(Selection.objects, "Rename");
                SetNewName(newNameInput);
            }
        }
        Repaint();//实时刷新
    }

    /// <summary>
    /// 查找或替换 
    /// </summary>
    /// <param name="index"></param>0查找 1替换
    /// <param name="findName"></param>查找名字
    /// <param name="replaceName"></param>替换后名字
    void FindOrReplace(int index, string findName, string replaceName)
    {
        ClearConsole();
        //获取所选中物体的数组
        selectedObjs = Selection.gameObjects;
        if (selectedObjs.Length == 0)
        {
            Debug.Log("<color=red>错误: </color>" + "没有选中任何物体!");
            return;
        }
        if (findName == string.Empty || findName == null)
        {
            Debug.Log("<color=red>错误: </color>" + "值不能为空!");
            return;
        }
        if (index == (int)PopupIndex.Repalce)
        {
            if (replaceName == string.Empty || replaceName == null)
            {
                Debug.Log("<color=red>错误: </color>" + "值不能为空!");
                return;
            }
        }

        //准备一个存放找到符合查询条件的集合
        List<GameObject> findedObjsArray = new List<GameObject>();
        //遍历是否包含查找的名字
        for (int i = 0; i < selectedObjs.Length; i++)
        {
            if (selectedObjs[i].transform.name.Contains(findName))
            {
                switch (index)
                {
                    case (int)PopupIndex.Find:
                        Debug.Log(selectedObjs[i].transform.name);
                        break;
                    case (int)PopupIndex.Repalce:
                        Debug.Log(selectedObjs[i].transform.name + "已替换为:" + "<color=green>" + replaceName + "</color>");
                        selectedObjs[i].transform.name = selectedObjs[i].transform.name.Replace(findName, replaceName);
                        break;
                }

                findedObjsArray.Add(selectedObjs[i]);
            }
        }
        Selection.objects = findedObjsArray.ToArray();
    }

    /// <summary>
    /// 全部重命名
    /// </summary>
    /// <param name="newInputName"></param>
    void SetNewName(string newInputName)
    {
        //前期准备工作
        ClearConsole();
        //获取所选中物体的数组
        selectedObjs = Selection.gameObjects;

        if (selectedObjs.Length == 0)
        {
            Debug.Log("<color=red>错误:</color>" + "没有选中任何物体!");
            return;
        }
        if (newInputName == string.Empty || newInputName == null)
        {
            Debug.Log("<color=red>错误:</color>" + "值不能为空!");
            return;
        }

        //遍历
        if (selectedObjs.Length == 1)
        {
            Debug.Log(selectedObjs[0].transform.name + "重命名为:" + "<color=green>" + newInputName + "</color>");
            selectedObjs[0].transform.name = newInputName;
        }
        else if (selectedObjs.Length > 1)
        {
            // 先拆分成一个一个根据父物体名字 分离的list
            Dictionary<string, List<GameObject>> splitedDic = SplitWithParent(selectedObjs);

            //遍历每一个父物体下的list
            foreach (List<GameObject> littleGroup in splitedDic.Values)
            {
                if (littleGroup.Count == 1)
                {
                    littleGroup[0].transform.name = newInputName;
                    Debug.Log(littleGroup[0].transform.name + "重命名为:" + "<color=green>" + newInputName + "</color>");
                }
                else
                {
                    //根据下标排序
                    GameObject[] trueSortObjs = SortGameObjs(littleGroup.ToArray());
                    //重命名
                    for (int i = 0; i < trueSortObjs.Length; i++)
                    {
                        Debug.Log(trueSortObjs[i].transform.name + "重命名为:" + "<color=green>" + newInputName + "_" + i + "</color>");
                        trueSortObjs[i].transform.name = newInputName + "_" + (i + startIndex).ToString();
                    }
                }
            }
        }
    }

    #region 辅助方法
    /// <summary>
    /// 清空log信息
    /// </summary>
    void ClearConsole()
    {
        if (clearMethod == null)
        {
            Type log = typeof(EditorWindow).Assembly.GetType("UnityEditor.LogEntries");
            clearMethod = log.GetMethod("Clear");
        }
        clearMethod.Invoke(null, null);
    }

    /// <summary>
    /// 数组排序 Slection.gameobjects是乱序 在部分时候需要通过下标重新排序
    /// </summary>
    /// <param name="targetObjs"></param>
    /// <returns></returns>
    GameObject[] SortGameObjs(GameObject[] targetObjs)
    {
        GameObject[] sortedObjs = targetObjs;
        GameObject temp;
        for (int i = 0; i < sortedObjs.Length - 1; i++)
        {
            for (int j = 0; j < sortedObjs.Length - i - 1; j++)
            {
                if (sortedObjs[j].transform.GetSiblingIndex() > sortedObjs[j + 1].transform.GetSiblingIndex())
                {
                    temp = sortedObjs[j + 1];
                    sortedObjs[j + 1] = sortedObjs[j];
                    sortedObjs[j] = temp;
                }
            }
        }
        return sortedObjs;
    }

    /// <summary>
    /// 根据传入数组的父物体名字分成更小的几个小组
    /// </summary>
    /// <param name="targetObjs"></param>
    /// <returns></returns>
    Dictionary<string, List<GameObject>> SplitWithParent(GameObject[] targetObjs)
    {
        Dictionary<string, List<GameObject>> splitedDic = new Dictionary<string, List<GameObject>>();

        // 遍历所有选中的物体
        for (int i = 0; i < targetObjs.Length; i++)
        {
            if (targetObjs[i].transform.parent != null)
            {
                if (!splitedDic.ContainsKey(targetObjs[i].transform.parent.name))
                {
                    List<GameObject> temp = new List<GameObject>();
                    temp.Add(targetObjs[i]);
                    splitedDic.Add(targetObjs[i].transform.parent.name, temp);
                }
                else
                {
                    splitedDic[targetObjs[i].transform.parent.name].Add(targetObjs[i]);
                }
            }
            else
            {
                if (!splitedDic.ContainsKey("NoParent"))
                {
                    List<GameObject> temp = new List<GameObject>();
                    temp.Add(targetObjs[i]);
                    splitedDic.Add("NoParent", temp);
                }
                else
                    splitedDic["NoParent"].Add(targetObjs[i]);
            }
        }

        return splitedDic;
    }
    #endregion
}
